package sskj.regulatory.presentation.widget

import android.content.Context
import android.util.AttributeSet
import android.view.MotionEvent
import android.view.SurfaceView
import com.hikvision.sdk.net.bean.CustomRect


/**
 *
 * 视频播放控件
 *
 * @author zhangwei59 2017/3/10 14:36
 * @version V1.0.0
 */
class CustomSurfaceView @JvmOverloads constructor(
        context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : SurfaceView(context, attrs, defStyleAttr) {

    private var mLastMotionY = 0f
    private var mLastMotionX = 0f
    private var mRatioX = 1f
    private var mRatioY = 1f

    private var mLastDis = 0f
    private var mLastScale = 1f
    private var mClickMode = TouchMode.NONE
    private var mActionPointerId = INVALID_POINTER
    private val mOriginalRect = CustomRect()
    private val mVirtualRect = CustomRect()
    private var mZoomListener: OnZoomListener? = null
    /**
     * 判断是否在等待双击 false - 表示单击，true - 表示双击
     */
    private var mWaitDouble = true
    /**
     * 用于判断click事件
     */
    private var mLastClickX: Float = 0.toFloat()
    /**
     * 用于判断click事件
     */
    private var mLastClickY: Float = 0.toFloat()



    /***
     * 设置电子放大监听，设置“null”时表示取消电子放大监听，设置有效的监听时，当前CustomSurfaceview会截获父控件的touch事件。
     * @param listener 监听者
     */
    fun setOnZoomListener(listener: OnZoomListener) {
        mZoomListener = listener

        if (mZoomListener == null) {
            mVirtualRect.setValue(mOriginalRect.left, mOriginalRect.top, mOriginalRect.right,
                    mOriginalRect.bottom)

            mLastMotionY = 0f
            mLastMotionX = 0f
            mLastDis = 0f
            mRatioX = 1f
            mRatioY = 1f
            mLastScale = 1f
        }
    }

    override fun onTouchEvent(ev: MotionEvent): Boolean {
        if (mZoomListener == null) {
            return false
        }

        if (!click(ev)) {// 点击事件未被“双击事件”消耗
            zoom(ev)
        }

        return true
    }

    override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {
        mOriginalRect.setValue(l.toFloat(), t.toFloat(), r.toFloat(), b.toFloat())
        if (changed) {
            mVirtualRect.setValue(l.toFloat(), t.toFloat(), r.toFloat(), b.toFloat())
        }

    }

    private fun click(ev: MotionEvent): Boolean {
        if (ev.pointerCount != 1) {
            return false
        }

        val action = ev.action
        var isEventConsume = false

        when (action and MotionEvent.ACTION_MASK) {
            MotionEvent.ACTION_DOWN -> {
                mLastClickX = ev.getX(0)
                mLastClickY = ev.getY(0)
            }
            MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> {
                val delateX = ev.getX(0) - mLastClickX
                val delateY = ev.getY(0) - mLastClickY
                if (isClick(delateX, delateY)) {
                    if (mWaitDouble) {
                        mWaitDouble = false
                        postDelayed(ProcessSingleClick(), DOUBLE_CLICK_TIME.toLong())
                    } else {
                        mWaitDouble = true

                        if (mLastScale == MAX_SCALE.toFloat()) {
                            midPointDoubleClick(ev)
                            scale(1f)
                        } else {
                            midPointDoubleClick(ev)
                            scale(MAX_SCALE.toFloat())
                        }

                        isEventConsume = true

                    }
                }
            }
            else -> {
            }
        }

        return isEventConsume

    }

    private fun zoom(ev: MotionEvent) {
        val action = ev.action

        when (action and MotionEvent.ACTION_MASK) {
            MotionEvent.ACTION_DOWN -> {
                mClickMode = TouchMode.ZOOM_DRAG

                if (ev.pointerCount < 1) {
                    return
                }

                mActionPointerId = ev.getPointerId(0)

                if (mActionPointerId < 0) {
                    return
                }

                mLastMotionX = ev.x
                mLastMotionY = ev.y
            }
            MotionEvent.ACTION_MOVE -> if (TouchMode.ZOOM_DRAG == mClickMode) {
                val index = ev.findPointerIndex(mActionPointerId)
                if (index < 0) {
                    return
                }

                val x = ev.getX(index)
                val y = ev.getY(index)

                move(mLastMotionX, mLastMotionY, x, y)

                mLastMotionX = x
                mLastMotionY = y
            } else if (TouchMode.ZOOM_SCALE == mClickMode) {
                if (ev.pointerCount != 2) {
                    return
                }

                val dis = spacing(ev)
                var scale = mLastScale + (dis - mLastDis) * UNIT_SCALE_RATIO

                mLastDis = dis

                if (scale < 1) {
                    scale = 1f
                }

                if (scale > MAX_SCALE) {
                    scale = MAX_SCALE.toFloat()
                }

                scale(scale)
                midPoint(ev)

            }
            MotionEvent.ACTION_UP -> {
            }
            MotionEvent.ACTION_CANCEL -> {
            }
            MotionEvent.ACTION_POINTER_DOWN -> {
                mLastDis = spacing(ev)
                mClickMode = TouchMode.ZOOM_SCALE
                midPoint(ev)
            }
            MotionEvent.ACTION_POINTER_UP -> {
                onSecondaryPointerUp(ev)
                mClickMode = TouchMode.ZOOM_DRAG
            }
        }
    }

    private fun spacing(event: MotionEvent): Float {
        if (event.pointerCount < 2) {
            return 0f
        }
        val x = event.getX(0) - event.getX(1)
        val y = event.getY(0) - event.getY(1)

        return Math.sqrt((x * x + y * y).toDouble()).toFloat()
    }

    private fun scale(newScale: Float) {
        val w = mOriginalRect.width * newScale
        val h = mOriginalRect.height * newScale

        val newL = mVirtualRect.left - mRatioX * (w - mVirtualRect.width)
        val newT = mVirtualRect.top - mRatioY * (h - mVirtualRect.height)
        val newR = newL + w
        val newB = newT + h

        mVirtualRect.setValue(newL, newT, newR, newB)

        judge(mOriginalRect, mVirtualRect)

        if (mZoomListener != null) {
            mLastScale = newScale
            mZoomListener!!.onZoomChange(mOriginalRect, mVirtualRect)
        }
    }

    private fun midPoint(event: MotionEvent) {
        val x = event.getX(0) + event.getX(1)
        val y = event.getY(0) + event.getY(1)

        mRatioX = Math.abs(x / 2 - mVirtualRect.left) / mVirtualRect.width
        mRatioY = Math.abs(y / 2 - mVirtualRect.top) / mVirtualRect.height

    }

    private fun midPointDoubleClick(event: MotionEvent) {
        val x = event.getX(0)
        val y = event.getY(0)

        mRatioX = Math.abs(x - mVirtualRect.left) / mVirtualRect.width
        mRatioY = Math.abs(y - mVirtualRect.top) / mVirtualRect.height
    }

    private fun move(lastX: Float, lastY: Float, curX: Float, curY: Float) {

        val deltaX = curX - lastX
        val deltaY = curY - lastY

        val left = mVirtualRect.left
        val top = mVirtualRect.top
        val right = mVirtualRect.right
        val bottom = mVirtualRect.bottom

        val newL = left + deltaX
        val newT = top + deltaY
        val newR = right + deltaX
        val newB = bottom + deltaY

        mVirtualRect.setValue(newL, newT, newR, newB)

        judge(mOriginalRect, mVirtualRect)

        if (mZoomListener != null) {
            mZoomListener!!.onZoomChange(mOriginalRect, mVirtualRect)
        }

    }

    private fun onSecondaryPointerUp(ev: MotionEvent) {
        val pointerIndex = ev.action and MotionEvent.ACTION_POINTER_INDEX_MASK shr MotionEvent.ACTION_POINTER_INDEX_SHIFT
        val pointerId = ev.getPointerId(pointerIndex)

        val newPointerIndex = if (pointerIndex == 0) 1 else 0
        mLastMotionX = ev.getX(newPointerIndex)
        mLastMotionY = ev.getY(newPointerIndex)
        if (pointerId == mActionPointerId) {
            mActionPointerId = ev.getPointerId(newPointerIndex)

        }

    }

    private fun judge(oRect: CustomRect, curRect: CustomRect) {

        val oL = oRect.left
        val oT = oRect.top
        val oR = oRect.right
        val oB = oRect.bottom

        var newL = curRect.left
        var newT = curRect.top
        var newR: Float
        var newB: Float

        val newW = curRect.width
        val newH = curRect.height

        if (newL > oL) {
            newL = oL
        }
        newR = newL + newW

        if (newT > oT) {
            newT = oT
        }
        newB = newT + newH

        if (newR < oR) {
            newR = oR
            newL = oR - newW
        }

        if (newB < oB) {
            newB = oB
            newT = oB - newH
        }
        curRect.setValue(newL, newT, newR, newB)
    }

    interface OnZoomListener {
        fun onZoomChange(oRect: CustomRect, curRect: CustomRect)
    }

    private enum class TouchMode {
        NONE, ZOOM_DRAG, ZOOM_SCALE
    }

    private inner class ProcessSingleClick : Runnable {

        override fun run() {
            if (!mWaitDouble) {
                mWaitDouble = true

                // 单击

            }
        }
    }

    /***
     * 判断是否是点击事件
     * @param deltaX 点击位置X坐标
     * @param deltaY 点击位置Y坐标
     * @return 是否为点击
     */
    private fun isClick(deltaX: Float, deltaY: Float): Boolean {
        return !(Math.abs(deltaX) > TOUCH_SLOP || Math.abs(deltaY) > TOUCH_SLOP)
    }

    companion object {

        private val INVALID_POINTER = -1
        private val UNIT_SCALE_RATIO = 0.003f

        private val TOUCH_SLOP = 30
        /**
         * 最大放大倍数
         */
        private val MAX_SCALE = 8
        /**
         * 双击事件间隔
         */
        private val DOUBLE_CLICK_TIME = 300
    }

}
